package com.qk.management.service.serviceimpl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qk.common.PageResult;
import com.qk.common.constant.BusinessStatusConstant;
import com.qk.common.enums.CommonVariablesEnum;
import com.qk.common.enums.ParamEnum;
import com.qk.common.exception.CommonException;
import com.qk.common.util.thread.CurrentLoggedInUserIDData;
import com.qk.dto.business.BusinessDTO;
import com.qk.dto.business.BusinessFollowDTO;
import com.qk.dto.business.BusinessInsertDTO;
import com.qk.dto.business.BusinessPoolDTO;
import com.qk.entity.Business;
import com.qk.entity.BusinessTrackRecord;
import com.qk.entity.Customer;
import com.qk.management.mapper.BusinessMapper;
import com.qk.management.mapper.BusinessTrackRecordsMapper;
import com.qk.management.mapper.CustomerMapper;
import com.qk.management.mapper.UserMapper;
import com.qk.management.service.BusinessService;
import com.qk.vo.business.BusinessByIdVO;
import com.qk.vo.business.BusinessTrackRecordVO;
import com.qk.vo.business.BusinessVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author 上官徵羽
 * @version 1.0
 * @since 2025-10-19 9:36
 */
@Service
public class BusinessServiceImpl extends ServiceImpl<BusinessMapper, Business> implements BusinessService {

    @Autowired
    private UserMapper userMapper;
    @Autowired
    private CustomerMapper customerMapper;
    @Autowired
    private BusinessTrackRecordsMapper businessTrackRecordsMapper;

    @Override
    public PageResult<BusinessVO> listPage(BusinessDTO businessDTO) {
        Page<Business> page = new Page<>(businessDTO.getPage(), businessDTO.getPageSize());
        LambdaQueryWrapper<Business> queryWrapper = new LambdaQueryWrapper<>();
        if (extracted(businessDTO, queryWrapper)) {
            return PageResult.<BusinessVO>builder()
                    .total(page.getTotal())
                    .rows(new ArrayList<>())
                    .build();
        }
        queryWrapper.eq(!ObjectUtil.isEmpty(businessDTO.getBusinessId()), Business::getId, businessDTO.getBusinessId())
                .eq(!ObjectUtil.isEmpty(businessDTO.getStatus()), Business::getStatus, businessDTO.getStatus())
                .like(!ObjectUtil.isEmpty(businessDTO.getName()), Business::getName, businessDTO.getName())
                .like(!ObjectUtil.isEmpty(businessDTO.getPhone()), Business::getPhone, businessDTO.getPhone());
        Page<Business> businessPage = this.baseMapper.selectPage(page, queryWrapper);
        Page<BusinessVO> businessPageVO = new Page<>();
        BeanUtil.copyProperties(businessPage, businessPageVO, CommonVariablesEnum.PAGE_FIELD_RECORDS.getKey());
        if (!ObjectUtil.isEmpty(businessPage.getRecords())) {
            businessPageVO.setRecords(businessPage.getRecords().stream()
                    .map(business -> {
                        BusinessVO businessVO = new BusinessVO();
                        BeanUtil.copyProperties(business, businessVO);
                        return businessVO;
                    }).collect(Collectors.toList()));
            setAssignName(businessPage, businessPageVO);
        }
        return PageResult.<BusinessVO>builder()
                .total(businessPage.getTotal())
                .rows(businessPageVO.getRecords())
                .build();
    }

    @Override
    public Object saveBusiness(BusinessInsertDTO businessInsertDTO) {
        if (ObjectUtil.isEmpty(businessInsertDTO.getPhone())) {
            CommonException.throwCommonException(ParamEnum.PARAM_ERROR);
        }
        Business business = BeanUtil.copyProperties(businessInsertDTO, Business.class);
        business.setCreateTime(LocalDateTime.now());
        business.setUpdateTime(LocalDateTime.now());
        business.setStatus(BusinessStatusConstant.BUSINESS_WAIT_ALLOT);
        this.baseMapper.insert(business);
        return null;
    }

    @Override
    public void allocationBusiness(Integer businessId, Integer userId) {
        this.baseMapper.updateById(Business.builder()
                .id(businessId)
                .userId(userId)
                .status(BusinessStatusConstant.BUSINESS_WAIT_FOLLOW)
                .updateTime(LocalDateTime.now())
                .createTime(LocalDateTime.now())
                .build());
    }

    @Override
    public void outBusiness(Integer businessId) {
        this.baseMapper.update(Wrappers.<Business>lambdaUpdate()
                .eq(Business::getId, businessId)
                .set(Business::getStatus, BusinessStatusConstant.BUSINESS_FALSE)
                .set(Business::getUpdateTime, LocalDateTime.now())
                .set(Business::getNextTime, null)
                .set(Business::getUserId, null));
    }

    @Override
    @Transactional
    public void toCustomer(Integer id) {
        Business business = this.baseMapper.selectById(id);
        Customer customer = BeanUtil.copyProperties(business, Customer.class);
        customer.setId(null);
        customer.setBusinessId(id);
        customer.setCreateTime(LocalDateTime.now());
        customer.setUpdateTime(LocalDateTime.now());
        this.customerMapper.insert(customer);
        this.baseMapper.update(Wrappers.<Business>lambdaUpdate()
                .eq(Business::getId, id)
                .set(Business::getStatus, BusinessStatusConstant.BUSINESS_CONVERT_CUSTOMER)
                .set(Business::getUpdateTime, LocalDateTime.now()));
    }

    @Override
    public BusinessByIdVO getBusinessById(Integer id) {
        Business business = this.baseMapper.selectById(id);
        BusinessByIdVO businessByIdVO = BeanUtil.copyProperties(business, BusinessByIdVO.class);
        List<BusinessTrackRecord> businessTrackRecordList = this.businessTrackRecordsMapper.selectList(Wrappers.<BusinessTrackRecord>lambdaQuery().eq(BusinessTrackRecord::getBusinessId, id));
        String assignName = userMapper.getById(business.getUserId()).getName();
        if (!ObjectUtil.isEmpty(businessTrackRecordList)) {
            businessByIdVO.setTrackRecords(businessTrackRecordList.stream()
                    .map(businessTrackRecord -> {
                                BusinessTrackRecordVO businessTrackRecordVO = BeanUtil.copyProperties(businessTrackRecord, BusinessTrackRecordVO.class);
                                businessTrackRecordVO.setAssignName(assignName);
                                return businessTrackRecordVO;
                            }
                    ).toList());
        }
        return businessByIdVO;
    }

    @Override
    @Transactional
    public void businessFollow(BusinessFollowDTO businessFollowDTO) {
        Business business = BeanUtil.copyProperties(businessFollowDTO, Business.class);
        BusinessTrackRecord businessTrackRecord = BeanUtil.copyProperties(businessFollowDTO, BusinessTrackRecord.class, "keyItems");
        business.setUpdateTime(LocalDateTime.now());
        business.setUserId(CurrentLoggedInUserIDData.get());
        businessTrackRecord.setCreateTime(LocalDateTime.now());
        if (ObjectUtil.equals(BusinessStatusConstant.BUSINESS_WAIT_FOLLOW, business.getStatus())) {
            business.setStatus(BusinessStatusConstant.BUSINESS_FOLLOWING);
        }
        if (ObjectUtil.isEmpty(businessFollowDTO.getKeyItems())) {
            business.setNextTime(null);
        } else {
            businessTrackRecord.setKeyItems(businessFollowDTO.getKeyItems().toString());
        }
        businessTrackRecord.setId(null);
        businessTrackRecord.setUserId(CurrentLoggedInUserIDData.get());
        businessTrackRecord.setBusinessId(businessFollowDTO.getId());
        this.baseMapper.updateById(business);
        this.businessTrackRecordsMapper.insert(businessTrackRecord);
    }

    @Override
    public PageResult<Business> businessPool(BusinessPoolDTO businessPoolDTO) {
        Page<Business> page = Page.of(businessPoolDTO.getPage(), businessPoolDTO.getPageSize());
        LambdaQueryWrapper<Business> queryWrapper = Wrappers.<Business>lambdaQuery()
                .eq(!ObjectUtil.isEmpty(businessPoolDTO.getBusinessId()), Business::getId, businessPoolDTO.getBusinessId())
                .like(!ObjectUtil.isEmpty(businessPoolDTO.getName()), Business::getName, businessPoolDTO.getName())
                .like(!ObjectUtil.isEmpty(businessPoolDTO.getPhone()), Business::getPhone, businessPoolDTO.getPhone())
                .eq(!ObjectUtil.isEmpty(businessPoolDTO.getSubject()), Business::getSubject, businessPoolDTO.getSubject());
        Page<Business> businessPage = this.baseMapper.selectPage(page, queryWrapper);
        return PageResult.<Business>builder()
                .total(businessPage.getTotal())
                .rows(businessPage.getRecords())
                .build();
    }

    private void setAssignName(Page<Business> businessPage, Page<BusinessVO> businessPageVO) {
        List<Integer> assignIds = businessPage.getRecords().stream()
                .map(Business::getUserId)
                .filter(ObjectUtil::isNotNull)
                .distinct()
                .toList();
        if (!ObjectUtil.isEmpty(assignIds)) {
            Map<Integer, String> userMap = getUserMap(null, assignIds);
            businessPageVO.setRecords(businessPageVO.getRecords().stream().peek(item ->
                    item.setAssignName(userMap.get(item.getUserId()))).toList());
        }
    }

    private boolean extracted(BusinessDTO businessDTO, LambdaQueryWrapper<Business> queryWrapper) {
        if (!ObjectUtil.isEmpty(businessDTO.getAssignName())) {
            Map<Integer, String> userMap = getUserMap(businessDTO.getAssignName(), null);
            if (ObjectUtil.isEmpty(userMap)) {
                return true;
            }
            queryWrapper.in(Business::getUserId, userMap.keySet());
        }
        return false;
    }

    private Map<Integer, String> getUserMap(String name, List<Integer> ids) {
        List<Map<String, Object>> map = userMapper.getMap(name, ids);
        return map.stream().collect(Collectors.toMap(
                item -> Integer.parseInt(item.get(CommonVariablesEnum.ID.getKey()).toString()),
                item -> item.get(CommonVariablesEnum.NAME.getKey()).toString()));
    }
}
